/*
 * Copyright 2009-2010 Original Author(s)
 * 
 * This file is part of Kommando
 * 
 * Kommando is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Kommando is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Kommando.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kommando.core;

import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import org.kommando.core.action.ActionRepository;
import org.kommando.core.catalog.Catalog;
import org.kommando.core.catalog.CatalogObject;
import org.kommando.core.command.Command;
import org.kommando.core.command.CommandExecutionException;
import org.kommando.core.command.DefaultCommandContext;
import org.kommando.core.search.DefaultResult;
import org.kommando.core.selector.CommandSelector;

/**
 * Default implementation of {@link Kommando}.
 * 
 * @author Peter De Bruycker
 */
public class DefaultKommando implements Kommando {
    private boolean clearSelection = true;

    private class KommandoKeyEventDispatcher implements KeyEventDispatcher {
        private final Catalog catalog;

        // guard is used to prevent recursive key handling
        private boolean guard;

        private KommandoKeyEventDispatcher(Catalog catalog) {
            this.catalog = catalog;
        }

        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (guard) {
                return false;
            }

            boolean handled = false;

            if (commandSelector.isVisible()) {
                try {
                    guard = true;
                    handled = commandSelector.handleKeyEvent(e);
                } finally {
                    guard = false;
                }
            }

            if (!handled) {
                if (e.getID() == KeyEvent.KEY_RELEASED) {
                    if (e.getModifiers() == 0 && e.getKeyCode() == KeyEvent.VK_ENTER) {
                        Command command = commandSelector.getSelectedCommand();
                        if (command != null) {
                            commandSelector.hide();
                            try {
                                command.execute(new DefaultCommandContext(DefaultKommando.this, catalog));
                                historyTracker.commandExecuted(commandSelector.getState());
                                clearSelection = true;
                            } catch (CommandExecutionException e1) {
                                // TODO handle exception
                                e1.printStackTrace();
                            }
                        }

                        return true;
                    }
                }
            }

            return handled;
        }
    }

    private CommandSelector commandSelector;
    private KommandoWindow window;

    private HistoryTracker historyTracker = new HistoryTracker();

    public DefaultKommando(final Catalog catalog, ActionRepository actionRepository) {
        commandSelector = new CommandSelector(catalog, actionRepository, historyTracker);

        installKeyDispatcher(catalog);
    }

    private void installKeyDispatcher(final Catalog catalog) {
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KommandoKeyEventDispatcher(catalog));
    }

    @Override
    public void summon() {
        commandSelector.show(clearSelection);

        clearSelection = false;
    }

    @Override
    public void summon(CatalogObject direct) {
        commandSelector.show(new DefaultResult<CatalogObject>(direct));

        clearSelection = false;
    }

    public void close() {
        System.exit(0);
    }

    @Override
    public Command getSelectedCommand() {
        return commandSelector.getSelectedCommand();
    }

    @Override
    public void setKommandoWindow(KommandoWindow window) {
        if (this.window != null) {
            window.dispose();
        }
        this.window = window;

        window.getWindowControl().addWindowListener(new WindowAdapter() {
            @Override
            public void windowDeactivated(WindowEvent e) {
                if (e.getOppositeWindow() == null) {
                    commandSelector.hide();
                }
            }
        });

        commandSelector.setWindow(window);
    }
}
